//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//------------------------------------------------------------------------------
//
// This file implements BootDisplay interface for Littleton. It encapsulates
// LCD controller and actual LCD panel used.
//
#include <windows.h>
#include <oal.h>
#include <monahans.h>
#include "xllp_defs.h"
#include "xllp_lcd.h"
#include "xllp_ost.h"
#include "xllp_i2c.h"
#include "GPX_xllp.h"
#include "xllp_pm_micco.h"
#include "lcd_defs.h"
#include "xllp_lcd_plat.h"
#include "boot.h"
#include "args.h"
#include "image_cfg.h"
#include "xllp_mfp_plat.h"
#include "xllp_gpio_plat.h"

extern "C"
{
#include "xllp_bkl_micco_B0.h"
}

//------------------------------------------------------------------------------

#define DISPLAY_COOKIE              'Disp'

//------------------------------------------------------------------------------

typedef struct DISPLAY {
    UINT32 cookie;                  // Cookie to verify handler
} DISPLAY;

//------------------------------------------------------------------------------

static DISPLAY s_display;
P_XLLP_OST_T s_pOST;
P_XLLP_I2C_T s_pI2C;

//------------------------------------------------------------------------------

BOOL
BootDisplayLittletonDeinit(
    HANDLE hDisplay
    );

BOOL
BootDisplayLittletonIoCtl(
    HANDLE hDisplay,
    DWORD code,
    VOID* pBuffer,
    DWORD size
    );

//------------------------------------------------------------------------------

static
BOOL
DisplayFillRect(
    DISPLAY* pDisplay,
    RECT* pRect,
    UINT32 color
    );

static
BOOL
DisplayBltRect(
    DISPLAY* pDisplay,
    RECT* pRect,
    VOID* pBuffer
    );

//------------------------------------------------------------------------------

static BOOT_DEVICE_IFC s_displayIfc = {
    &s_display,
    BootDisplayLittletonDeinit,
    NULL,
    NULL,
    NULL,
    NULL,
    BootDisplayLittletonIoCtl
};

//------------------------------------------------------------------------------

extern XLLP_STATUS_T XllpLCDInit(P_XLLP_LCD_T pXllpLCD);
extern void XllpLCDSuspend(P_XLLP_LCD_T pXllpLCD, int SuspendType);
extern void XllpLCDResume(P_XLLP_LCD_T pXllpLCD);
extern XLLP_STATUS_T XllpMfpResourceManagerInit (P_XLLP_MFP_RM_DB_ID_T  pMfpRmDb);
extern XLLP_STATUS_T XllpI2cInit(P_XLLP_I2C_T I2C_regs,  P_XLLP_VUINT32_T pMfpRegBase, P_XLLP_MFP_RM_DB_ID_T pMfpRmDb, XLLP_UINT32_T dev_id); 
extern XLLP_STATUS_T XllpPmMiccoWrite(XLLP_I2C_T *i2cRegs, XLLP_OST_T *ostRegs, XLLP_UINT8_T reg, XLLP_UINT8_T val);

static XLLP_STATUS_T LCDInitPinsTFT(P_XLLP_LCD_T pXllpLCD);
static XLLP_STATUS_T LCDInitPinsSMART(P_XLLP_LCD_T pXllpLCD);

XLLP_LCD_T XllpLCD;
XLLP_STATUS_T status;

DWORD g_DisplayBasePhysical = 0;
DWORD g_DisplayBaseVirtual = 0;

//------------------------------------------------------------------------------

VOID BacklightInit()
{
    XLLP_VUINT32_T *pMFP;
    XLLP_INT8_T pMfpRMDb[XLLP_MFP_RM_DB_SIZE];
    //TODO: Add Backlight code if necessary.
    s_pOST =  (P_XLLP_OST_T)MONAHANS_BASE_REG_PA_OST;
	s_pI2C =  (P_XLLP_I2C_T)MONAHANS_BASE_REG_PA_I2C;

	pMFP= (XLLP_VUINT32_T *) OALPAtoVA(MONAHANS_BASE_REG_PA_MFP, FALSE);

	if (XLLP_STATUS_SUCCESS!=XllpMfpResourceManagerInit(pMfpRMDb))
	{
	}
	XllpI2cInit(s_pI2C, pMFP, pMfpRMDb,0);
}

VOID BacklightOn()
{
    //TODO: Add Backlight code if necessary.
   XllpPmMiccoWrite(s_pI2C, s_pOST, 0x3c, 0x7f);
	XllpPmMiccoWrite(s_pI2C, s_pOST, 0x3d, 0x35);

}

VOID BacklightOff()
{
    //TODO: Add Backlight code if necessary.
    XllpPmMiccoWrite(s_pI2C, s_pOST, 0x3c, 0x00);
	XllpPmMiccoWrite(s_pI2C, s_pOST, 0x3d, 0x00);
}

//------------------------------------------------------------------------------

static void LCDPanelSelect()
{
    /* Todo: Fix it for Littleton */
    DWORD cfg;
    BSP_ARGS *pArgs = (BSP_ARGS *)IMAGE_SHARE_ARGS_PA_START;

    cfg = pArgs->eBootCFG.drvCfg[CFG_LCD_PANEL];

    XllpLCDInitTopoly(&XllpLCD, cfg);

}

//------------------------------------------------------------------------------

BOOL
BootDisplayLittletonInit(
    VOID* pContext,
    DWORD contextSize,
    BOOT_DEVICE_IFC **ppIfc
    )
{
    BOOL rc = FALSE;
    BOOT_DISPLAY_LITTLETON_INIT_CONTEXT *pInitContext = (BOOT_DISPLAY_LITTLETON_INIT_CONTEXT *)pContext;
    RECT rect;


    // Check parameter
    if (ppIfc == NULL) goto cleanUp;
    *ppIfc = NULL;

    // Check context
    if ((pContext == NULL) ||
        (contextSize != sizeof(BOOT_DISPLAY_LITTLETON_INIT_CONTEXT)))
        {
        OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonInit: "
            L"Unsupported init context size!\r\n"
            ));
        goto cleanUp;
        }

    // Create store context
    memset(&s_display, 0, sizeof(DISPLAY));
    s_display.cookie = DISPLAY_COOKIE;

    if( DISPLAY_SDRAM_REGION_SIZE > IMAGE_RSVD_DISPLAY_BUFFER_SIZE )
        {
        OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonInit: "
            L"SDRAM reserved display buffer is too small!\r\n"
            ));
        }

    // Fill XllpLCD structure with configuration information
    g_DisplayBasePhysical = IMAGE_RSVD_DISPLAY_BUFFER_PA;
    g_DisplayBaseVirtual = IMAGE_RSVD_DISPLAY_BUFFER_PA;

    XllpLCD.GPIO = (XLLP_VUINT32_T *) MONAHANS_BASE_REG_PA_GPIO;
    XllpLCD.CLKMan = (XLLP_VUINT32_T *) MONAHANS_BASE_REG_PA_CLKMGR;
    XllpLCD.LCDC = (XLLP_VUINT32_T *) MONAHANS_BASE_REG_PA_LCD;
    XllpLCD.OST = (XLLP_VUINT32_T *) MONAHANS_BASE_REG_PA_OST;
    XllpLCD.MFP = (XLLP_VUINT32_T *) MONAHANS_BASE_REG_PA_MFP;
    XllpLCD.SSP = (XLLP_VUINT32_T *) MONAHANS_BASE_REG_PA_SSP2;
	XllpLCD.I2C = (XLLP_VUINT32_T *) MONAHANS_BASE_REG_PA_I2C;

    XllpLCD.BPP = BPP_16;
    XllpLCD.PixelDataFormat = PDFOR_00; //with overlays enabled use PDFOR_11 for 16bpp

    XllpLCD._FRAME_BUFFER_BASE_PHYSICAL = FRAME_BUFFER_0_BASE_PHYSICAL;
    XllpLCD._PALETTE_BUFFER_BASE_PHYSICAL = PALETTE_BUFFER_BASE_PHYSICAL;
    XllpLCD._DMA_CHANNEL_0_FRAME_DESCRIPTOR_BASE_PHYSICAL = DMA_CHANNEL_0_FRAME_DESCRIPTOR_BASE_PHYSICAL;
    XllpLCD._DMA_CHANNEL_0_ALT_FRAME_DESCRIPTOR_BASE_PHYSICAL = DMA_CHANNEL_0_ALT_FRAME_DESCRIPTOR_BASE_PHYSICAL;
    XllpLCD._PALETTE_FRAME_DESCRIPTOR_BASE_PHYSICAL = PALETTE_FRAME_DESCRIPTOR_BASE_PHYSICAL;

    XllpLCD.frameDescriptorCh0fd1 = (LCD_FRAME_DESCRIPTOR *)(DMA_CHANNEL_0_FRAME_DESCRIPTOR_BASE_PHYSICAL);
    XllpLCD.frameDescriptorCh0fd2 = (LCD_FRAME_DESCRIPTOR *)(DMA_CHANNEL_0_ALT_FRAME_DESCRIPTOR_BASE_PHYSICAL);
    XllpLCD.frameDescriptorPalette = (LCD_FRAME_DESCRIPTOR *)(PALETTE_FRAME_DESCRIPTOR_BASE_PHYSICAL);

    XllpLCD.pMfpRmDb = (P_XLLP_MFP_RM_DB_ID_T) g_pMfpRmDb;

    if (!g_MfpRmDbInitialized && (XLLP_STATUS_SUCCESS != XllpMfpResourceManagerInit(XllpLCD.pMfpRmDb))) 
        {
        OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonInit: "
            L"IPL Display driver failed in XllpMfpResourceManagerInit\r\n"
            ));
        goto cleanUp;
        }
    else
        {
        g_MfpRmDbInitialized = TRUE;
        }
    
    // Choose among several Littleton panels and Initialize
    LCDPanelSelect();

    // Initialize the LCD Controller
    if( XLLP_STATUS_SUCCESS != XllpLCDInit(&XllpLCD) ) 
        {
        OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonInit: "
            L"XllpLCDInit returned 0x%x instead of success\r\n", 
            status));
        }
    
    // Set base background color
    rect.top = 0;
    rect.left = 0;
    rect.right = XllpLCD.panel->any.width - 1;
    rect.bottom = XllpLCD.panel->any.height - 1;
    DisplayFillRect(&s_display, &rect, 0x0000);

    // Take care of the backlight
    BacklightInit();
    BacklightOn();
      /*while(1)
	   	{
       if(XllpGpioExpanderSetOutputLevel((XLLP_I2C_T*)XllpLCD.I2C, (XLLP_OST_T*)XllpLCD.OST,XLLP_GPIO_GPS_POWERON, XLLP_HI) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_GPS_POWERON HI FAIL\r\n")));
        }
	   XllpOstDelayMilliSeconds((XLLP_OST_T*)XllpLCD.OST,1000);
	   if(XllpGpioExpanderSetOutputLevel((XLLP_I2C_T*)XllpLCD.I2C, (XLLP_OST_T*)XllpLCD.OST,XLLP_GPIO_GPS_POWERON, XLLP_LO) != XLLP_STATUS_SUCCESS)
        {
            RETAILMSG(1, (_T("Set XLLP_GPIO_GPS_POWERON LO FAIL\r\n")));
        }
	   XllpOstDelayMilliSeconds((XLLP_OST_T*)XllpLCD.OST,1000);
	   	}*/
    // Done
    *ppIfc = &s_displayIfc;
    rc = TRUE;

cleanUp:
    return rc;
}

//------------------------------------------------------------------------------

BOOL
BootDisplayLittletonDeinit(
    HANDLE hDisplay
    )
{
    BOOL rc = FALSE;
    DISPLAY *pDisplay = (DISPLAY*)hDisplay;

    // Check display handle
    if ((pDisplay == NULL) || (pDisplay->cookie != DISPLAY_COOKIE))
        {
        OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonDeinit: "
            L"Invalid display handle!\r\n"
            ));
        goto cleanUp;
        }

    BacklightOff();

    // Stop LCD controller
    XllpLCDSuspend(&XllpLCD,Suspend_Graceful);

    // Clear context
    memset(pDisplay, 0, sizeof(DISPLAY));

    // Done
    rc = TRUE;

cleanUp:
    return rc;
}

//------------------------------------------------------------------------------

BOOL
BootDisplayLittletonIoCtl(
    HANDLE hDisplay,
    DWORD code,
    VOID* pBuffer,
    DWORD size
    )
{
    BOOL rc = FALSE;
    DISPLAY *pDisplay = (DISPLAY*)hDisplay;

    // Check display handle
    if ((pDisplay == NULL) || (pDisplay->cookie != DISPLAY_COOKIE))
        {
        OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonIoCtl: "
            L"Invalid display handle!\r\n"
            ));
        goto cleanUp;
        }

    switch (code)
        {
        case BOOT_DISPLAY_IOCTL_FILLRECT:
            {
            BOOT_DISPLAY_FILLRECT_PARAMS* pParams;

            // Check input parameter
            if (pBuffer == NULL || size < sizeof(BOOT_DISPLAY_FILLRECT_PARAMS))
                {
                OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonIoCtl: "
                    L"BOOT_DISPLAY_IOCTL_FILLRECT - Invalid parameters!\r\n"
                    ));
                break;
                }
            pParams = (BOOT_DISPLAY_FILLRECT_PARAMS*)pBuffer;
            rc = DisplayFillRect(pDisplay, pParams->pRect, pParams->color);
            }
            break;
        case BOOT_DISPLAY_IOCTL_BLTRECT:
            {
            BOOT_DISPLAY_BLTRECT_PARAMS* pParams;

            // Check input parameter
            if (pBuffer == NULL || size < sizeof(BOOT_DISPLAY_BLTRECT_PARAMS))
                {
                OALMSG(OAL_ERROR, (L"ERROR: BootDisplayLittletonIoCtl: "
                    L"BOOT_DISPLAY_IOCTL_BLTRECT - Invalid parameters!\r\n"
                    ));
                break;
                }
            pParams = (BOOT_DISPLAY_BLTRECT_PARAMS*)pBuffer;
            rc = DisplayBltRect(pDisplay, pParams->pRect, pParams->pBuffer);
            }
            break;
        case BOOT_DISPLAY_IOCTL_SLEEP:
            XllpLCDSuspend(&XllpLCD, Suspend_Graceful);
            rc = TRUE;
            break;
        case BOOT_DISPLAY_IOCTL_AWAKE:
            XllpLCDResume(&XllpLCD);
            rc = TRUE;
            break;
        }

cleanUp:
    return rc;
}

//------------------------------------------------------------------------------

static
BOOL
DisplayFillRect(
    DISPLAY* pDisplay,
    RECT* pRect,
    UINT32 color
    )
{
    volatile USHORT *pFrame = (USHORT *)(FRAME_BUFFER_0_BASE_PHYSICAL);
    UINT32 screenWidth = XllpLCD.panel->any.width;
    LONG xt, yt;

    for (yt = pRect->top; yt < pRect->bottom; yt++)
        {
        for (xt = pRect->left; xt < pRect->right; xt++)
            {
            pFrame[yt * screenWidth + xt] = (UINT16)color;
            }
        }

    return TRUE;
}

//------------------------------------------------------------------------------

static
BOOL
DisplayBltRect(
    DISPLAY* pDisplay,
    RECT* pRect,
    VOID* pBuffer
    )
{
    volatile USHORT *pFrame = (USHORT *)(FRAME_BUFFER_0_BASE_PHYSICAL);
    UINT32 screenWidth = XllpLCD.panel->any.width;
    USHORT *pData = (USHORT*)pBuffer;
    LONG stride, pos, xt, yt;

    // Convert stride from bytes to words
    stride = pRect->right - pRect->left;
    pos = (pRect->bottom - pRect->top) * stride;

    for (yt = pRect->top; yt < pRect->bottom; yt++)
        {
        for (xt = pRect->right - 1; xt >= pRect->left; xt--)
            {
            pFrame[yt * screenWidth + xt] = pData[--pos];
            }
        }

   return TRUE;
}

